package jmine.tec.script.persistent.domain;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import jmine.tec.persist.annotation.Alias;
import jmine.tec.persist.annotation.Comment;
import jmine.tec.persist.annotation.Comments;
import jmine.tec.persist.annotation.UniqueConstraint;
import jmine.tec.script.persistent.dao.ScriptPurposeIdentifier;

import org.hibernate.Hibernate;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

import bancosys.tec.component.Documentation;
import bancosys.tec.persist.bussobj.PersistableBusinessObject;
import bancosys.tec.persist.persister.annotation.NaturalKey;
import bancosys.tec.persist.persister.annotation.SystemId;

/**
 * Entidade que designa o propósito do script.
 * 
 * @author lundberg
 */
@Entity
@Table(name = "SCRIPT_PURPOSE")
@Alias("SCRPUR")
@SequenceGenerator(name = "SEQ_SCRPUR", sequenceName = "SEQ_SCRPUR")
@Documentation("PROPOSITOS DE SCRIPTS.")
public class ScriptPurpose extends PersistableBusinessObject {

    private Long id;

    private String mnemonico;

    private String executionContext;

    private String dependencyContext;

    private String validationContext;

    private Set<Script> initScripts;

    private Map<ScriptLanguage, Script> initScriptMap;

    /**
     * @return the id
     */
    @Id
    @SystemId
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SCRPUR")
    @Column(name = "COD_SCRIPT_PURPOSE", nullable = false)
    @Documentation("CODIGO DO PROPOSITO DE SCRIPT.")
    public Long getId() {
        return this.id;
    }

    /**
     * @return the mnemonico
     */
    @NaturalKey
    @UniqueConstraint(name = "AK_SCRPUR_0")
    @Column(name = "MNE", nullable = false)
    @Documentation("MNEMONICO DO PROPOSITO DE SCRIPT.")
    public String getMnemonico() {
        return this.mnemonico;
    }

    /**
     * @return the executionContext
     */
    @Column(name = "EXEC_CTX")
    @Documentation("NOME DA CLASSE DO CONTEXTO DE EXECUCAO DO SCRIPT.")
    public String getExecutionContext() {
        return this.executionContext;
    }

    /**
     * @return the dependencyContext
     */
    @Column(name = "DEP_CTX")
    @Documentation("NOME DA CLASSE DO CONTEXTO DE DEPENDENCIAS DO SCRIPT.")
    public String getDependencyContext() {
        return this.dependencyContext;
    }

    /**
     * @return the validationContext
     */
    @Column(name = "VAL_CTX")
    @Documentation("NOME DA CLASSE DO CONTEXTO DE VALIDACAO DO SCRIPT.")
    public String getValidationContext() {
        return this.validationContext;
    }

    /**
     * @return the initScripts
     */
    @OneToMany
    @JoinTable(name = "PURPOSE_INIT_SCRIPTS", joinColumns = @JoinColumn(name = "COD_SCRIPT_PURPOSE", nullable = false), inverseJoinColumns = @JoinColumn(name = "COD_SCRIPT", nullable = false))
    @Alias("PUISCT")
    @Comments({
            @Comment(table = "PURPOSE_INIT_SCRIPTS", column = "COD_SCRIPT", value = "CODIGO DO SCRIPT."),
            @Comment(table = "PURPOSE_INIT_SCRIPTS", column = "COD_SCRIPT_PURPOSE", value = "CODIGO DO PROPOSITO DE SCRIPT."),
            @Comment(table = "PURPOSE_INIT_SCRIPTS", value = "TABELA DE ASSOCIACAO ENTRE UM PROPOSITO DE SCRIPT E OS "
                    + "SCRIPTS DE INICIALIZACAO EM CADA LINGUAGEM.") })
    @Cascade(CascadeType.LOCK)
    @UniqueConstraint(suffix = "0", columns = "COD_SCRIPT")
    protected Set<Script> getInitScripts() {
        if (this.initScripts == null) {
            this.initScripts = new HashSet<Script>();
        }
        return this.initScripts;
    }

    /**
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @param mnemonico the mnemonico to set
     */
    public void setMnemonico(String mnemonico) {
        this.mnemonico = mnemonico;
    }

    /**
     * @param executionContext the executionContext to set
     */
    public void setExecutionContext(String executionContext) {
        this.executionContext = executionContext;
    }

    /**
     * @param dependencyContext the dependencyContext to set
     */
    public void setDependencyContext(String dependencyContext) {
        this.dependencyContext = dependencyContext;
    }

    /**
     * @param validationContext the validationContext to set
     */
    public void setValidationContext(String validationContext) {
        this.validationContext = validationContext;
    }

    /**
     * @param initScripts the initScripts to set
     */
    protected void setInitScripts(Set<Script> initScripts) {
        this.initScripts = initScripts;
        this.initScriptMap = null;
    }

    /**
     * Adiciona um initScript ao purpose
     * 
     * @param script script
     */
    public void addInitScript(Script script) {
        this.getInitScripts().add(script);
        this.initScriptMap = null;
    }

    /**
     * Obtém o script de inicialização para a linguagem dada.
     * 
     * @param language language
     * @return script
     */
    @Transient
    public Script getInitScript(ScriptLanguage language) {
        return this.getInitScriptMap().get(language);
    }

    /**
     * @return true if the initializer script is loaded
     */
    public boolean initScriptInitialized() {
        return Hibernate.isInitialized(this.initScripts);
    }

    /**
     * Obtém o mapa de linguagem para script de inicialização
     * 
     * @return Map de ScriptLanguage para Script
     */
    @Transient
    private Map<ScriptLanguage, Script> getInitScriptMap() {
        if (this.initScriptMap == null) {
            this.initScriptMap = new HashMap<ScriptLanguage, Script>();
            for (Script scr : this.getInitScripts()) {
                this.initScriptMap.put(scr.getLanguage(), scr);
            }
        }
        return this.initScriptMap;
    }

    /**
     * Verifica se este propósito é identificado pelo identificador dado.
     * 
     * @param identifier identifier
     * @return boolean
     */
    @Transient
    public boolean isIdentifiedBy(ScriptPurposeIdentifier identifier) {
        return this.getId().equals(identifier.getSystemId());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return "ScriptPurpose: " + this.getMnemonico();
    }
}
